{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## About this workflow\n",
    "\n",
    "Earth engine couldnt load collection when I first (1) filter date-get collection & then (2)filter geometry-get collection. Because step one was resulting with too many data. So reversing the steps worked. In this case we:\n",
    "\n",
    "* Merge all Landsat collections (dataframe function)\n",
    "* Mapbox setup & create \"id\" variables to be used in Dash\n",
    "* HTML Function to return outputs from interactive tools\n",
    "    * Map, Base Layer, Clicked Coordinate, Max Cloud, Date Range\n",
    "* App Callbacks:\n",
    "    * Return clicked marker (dl.Marker) & global lat lon variables\n",
    "    * Return clciked coordinate (json.dumps(e))\n",
    "    * Return base layer (url)\n",
    "    * Return date\n",
    "* First filter feature collection with geometry (coordinates & cloud)\n",
    "* Then filter the resulting collection furhter with date range\n",
    "* Calculate NDWI, simplify dataframe \n",
    "* PLot simplified dataframe\n",
    "\n",
    "## Links\n",
    "\n",
    "* Returning HTML in a functins before calling the app: https://github.com/mepearson/tacc_dash/blob/fd12ece9555fe88d76f4550679295d8a73406120/viz/models/leaflet/render.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "##-----------------------------------------##\n",
    "#               Packages\n",
    "##-----------------------------------------##\n",
    "from datetime import datetime as dt\n",
    "import dash\n",
    "import dash_html_components as html\n",
    "import dash_core_components as dcc\n",
    "from dash.dependencies import Input, Output\n",
    "import dash_table\n",
    "import dash_leaflet as dl\n",
    "from dash.dependencies import Output, Input\n",
    "\n",
    "from IPython.display import Image\n",
    "from IPython.display import display\n",
    "import ipywidgets as widgets\n",
    "\n",
    "import ee, datetime\n",
    "from datetime import date\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import geopandas as gpd\n",
    "import matplotlib.pyplot as plt\n",
    "from shapely.geometry import Point\n",
    "\n",
    "#import eeconvert # Package to conver Earth Engine collection to dataframe or geodataframe\n",
    "import json\n",
    "\n",
    "import plotly.graph_objects as go\n",
    "from plotly.subplots import make_subplots\n",
    "import plotly.express as px\n",
    "\n",
    "\n",
    "# Earth Engine Python API\n",
    "ee.Initialize()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app \"__main__\" (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on http://127.0.0.1:8150/ (Press CTRL+C to quit)\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:06] \"\u001b[37mGET / HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mGET /_dash-layout HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mGET /_dash-dependencies HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:07] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception on /_dash-update-component [POST]\n",
      "Traceback (most recent call last):\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 2446, in wsgi_app\n",
      "    response = self.full_dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1951, in full_dispatch_request\n",
      "    rv = self.handle_user_exception(e)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1820, in handle_user_exception\n",
      "    reraise(exc_type, exc_value, tb)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/_compat.py\", line 39, in reraise\n",
      "    raise value\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1949, in full_dispatch_request\n",
      "    rv = self.dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1935, in dispatch_request\n",
      "    return self.view_functions[rule.endpoint](**req.view_args)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1407, in dispatch\n",
      "    response.set_data(self.callback_map[output][\"callback\"](*args))\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1294, in add_context\n",
      "    output_value = func(*args, **kwargs)  # %% callback invoked %%\n",
      "  File \"<ipython-input-4-94fe542c282e>\", line 179, in update_output\n",
      "    end_date = dt.strptime(end_date.split('T')[0], '%Y-%m-%d')\n",
      "AttributeError: 'NoneType' object has no attribute 'split'\n",
      "Exception on /_dash-update-component [POST]\n",
      "Traceback (most recent call last):\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 2446, in wsgi_app\n",
      "    response = self.full_dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1951, in full_dispatch_request\n",
      "    rv = self.handle_user_exception(e)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1820, in handle_user_exception\n",
      "    reraise(exc_type, exc_value, tb)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/_compat.py\", line 39, in reraise\n",
      "    raise value\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1949, in full_dispatch_request\n",
      "    rv = self.dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1935, in dispatch_request\n",
      "    return self.view_functions[rule.endpoint](**req.view_args)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1407, in dispatch\n",
      "    response.set_data(self.callback_map[output][\"callback\"](*args))\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1294, in add_context\n",
      "    output_value = func(*args, **kwargs)  # %% callback invoked %%\n",
      "  File \"<ipython-input-4-94fe542c282e>\", line 179, in update_output\n",
      "    end_date = dt.strptime(end_date.split('T')[0], '%Y-%m-%d')\n",
      "AttributeError: 'NoneType' object has no attribute 'split'\n",
      "Exception on /_dash-update-component [POST]\n",
      "Traceback (most recent call last):\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 2446, in wsgi_app\n",
      "    response = self.full_dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1951, in full_dispatch_request\n",
      "    rv = self.handle_user_exception(e)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1820, in handle_user_exception\n",
      "    reraise(exc_type, exc_value, tb)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/_compat.py\", line 39, in reraise\n",
      "    raise value\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1949, in full_dispatch_request\n",
      "    rv = self.dispatch_request()\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/flask/app.py\", line 1935, in dispatch_request\n",
      "    return self.view_functions[rule.endpoint](**req.view_args)\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1407, in dispatch\n",
      "    response.set_data(self.callback_map[output][\"callback\"](*args))\n",
      "  File \"/Users/nat/opt/anaconda3/envs/thesis/lib/python3.7/site-packages/dash/dash.py\", line 1294, in add_context\n",
      "    output_value = func(*args, **kwargs)  # %% callback invoked %%\n",
      "  File \"<ipython-input-4-94fe542c282e>\", line 179, in update_output\n",
      "    end_date = dt.strptime(end_date.split('T')[0], '%Y-%m-%d')\n",
      "AttributeError: 'NoneType' object has no attribute 'split'\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "127.0.0.1 - - [14/Apr/2020 11:46:08] \"\u001b[35m\u001b[1mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 500 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:09] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:09] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Click:Marker: [-15.156973713377667, 46.41517639160157]\n",
      " -15.156973713377667\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "127.0.0.1 - - [14/Apr/2020 11:46:11] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n",
      "127.0.0.1 - - [14/Apr/2020 11:46:11] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Your inputs return 579 images\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "127.0.0.1 - - [14/Apr/2020 11:46:27] \"\u001b[37mPOST /_dash-update-component HTTP/1.1\u001b[0m\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                NDWI       Time\n",
      "time_stamp                     \n",
      "2000-12-31  0.377932 2000-12-31\n",
      "2001-12-31  0.341532 2001-12-31\n",
      "2002-12-31  0.373659 2002-12-31\n",
      "2003-12-31  0.343228 2003-12-31\n",
      "2004-12-31  0.400738 2004-12-31\n",
      "2005-12-31  0.329197 2005-12-31\n",
      "2006-12-31  0.343874 2006-12-31\n",
      "2007-12-31  0.406181 2007-12-31\n",
      "2008-12-31  0.364645 2008-12-31\n",
      "2009-12-31  0.435978 2009-12-31\n",
      "2010-12-31  0.369869 2010-12-31\n",
      "2011-12-31  0.356317 2011-12-31\n",
      "2012-12-31  0.440177 2012-12-31\n",
      "2013-12-31  0.409303 2013-12-31\n",
      "2014-12-31  0.389762 2014-12-31\n",
      "2015-12-31  0.346242 2015-12-31\n",
      "2016-12-31  0.337563 2016-12-31\n",
      "2017-12-31  0.367494 2017-12-31\n",
      "2018-12-31  0.323282 2018-12-31\n",
      "2019-12-31  0.379718 2019-12-31\n"
     ]
    }
   ],
   "source": [
    "##-----------------------------------------##\n",
    "#               Collection Attributes\n",
    "##-----------------------------------------##\n",
    "\n",
    "\n",
    "def makeLandsatSeries():\n",
    "\n",
    "    lt4 = ee.ImageCollection('LANDSAT/LT04/C01/T1_SR')\n",
    "    lt5 = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR')\n",
    "    le7 = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR')\n",
    "    lc8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR')\n",
    "\n",
    "    lt4 = lt4.select(['B1','B2','B3','B4','B5','B7','pixel_qa'],['blu','grn','red','nir','swir1','swir2','pixel_qa'])\n",
    "    lt5 = lt5.select(['B1','B2','B3','B4','B5','B7','pixel_qa'],['blu','grn','red','nir','swir1','swir2','pixel_qa'])\n",
    "    le7 = le7.select(['B1','B2','B3','B4','B5','B7','pixel_qa'],['blu','grn','red','nir','swir1','swir2','pixel_qa'])\n",
    "    lc8 = lc8.select(['B2','B3','B4','B5','B6','B7','pixel_qa'],['blu','grn','red','nir','swir1','swir2','pixel_qa'])\n",
    "\n",
    "    fullCollection = ee.ImageCollection(lt4.merge(lt5).merge(le7).merge(lc8))\n",
    "    return fullCollection\n",
    "\n",
    "\n",
    "##-----------------------------------------##\n",
    "#               Mapbox Attributes\n",
    "##-----------------------------------------##\n",
    "\n",
    "external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css',\n",
    "'https://codepen.io/chriddyp/pen/brPBPO.css']\n",
    "\n",
    "\n",
    "# Mapbox setup\n",
    "mapbox_url = \"https://api.mapbox.com/styles/v1/mapbox/{id}/tiles/{{z}}/{{x}}/{{y}}{{r}}?access_token={access_token}\"\n",
    "mapbox_token = 'pk.eyJ1IjoibmF0MSIsImEiOiJjazhpeDdwZ3gwM3FyM2RueTZwdDJ0bzB2In0.lqoQJb90lcn0cu-zulXWyw'\n",
    "mapbox_ids = [\"light-v9\", \"dark-v9\", \"streets-v9\", \"outdoors-v9\", \"satellite-streets-v9\"]\n",
    "\n",
    "# Element mapbox_ids\n",
    "BASE_LAYER_ID = \"base-layer-id\"\n",
    "BASE_LAYER_DROPDOWN_ID = \"base-layer-drop-down-id\"\n",
    "MAP_ID = \"map-id\"\n",
    "MARKER = \"marker-id\"\n",
    "NEW_MARKER= \"new-marker-id\"\n",
    "COORDINATE_CLICK_ID = \"coordinate-click-id\"\n",
    "\n",
    "\n",
    "##-----------------------------------------##\n",
    "#               Functions\n",
    "##-----------------------------------------##\n",
    "\n",
    "#Generate map functions\n",
    "def render_marker():\n",
    "    return [\n",
    "        dl.Map(id=MAP_ID, style={'width': '1000px', 'height': '500px'},\n",
    "               center=[-13, 48],\n",
    "               zoom = 5,\n",
    "               children=[\n",
    "                   dl.TileLayer(id=BASE_LAYER_ID),\n",
    "                   dl.Marker(id=MARKER, position=[56, 9.8], interactive=True,   opacity=0.8),\n",
    "                   html.Div(id=NEW_MARKER)\n",
    "                  \n",
    "               ]),\n",
    "        html.P(\"Coordinate (click on map):\"),\n",
    "        html.Div(id=COORDINATE_CLICK_ID),\n",
    "        \n",
    "        html.Div(\n",
    "            [ \n",
    "                dcc.Input(id=\"cloud\", type=\"number\", placeholder=\"cloud\",\n",
    "                          min = 0, max = 100, step = 10,),\n",
    "                #html.Hr(),\n",
    "                html.Div(id=\"number-out\"),\n",
    "            ]),\n",
    "        html.Div(\n",
    "            [\n",
    "                dcc.DatePickerRange(\n",
    "                    id='my-date-picker-range',\n",
    "                    #month_format='Do MMM, YYYY',\n",
    "                    display_format=\"YYYY,MM,DD\",\n",
    "                    min_date_allowed=dt(1995,1,1),\n",
    "                    max_date_allowed=dt.today(),\n",
    "                    #initial_visible_month=dt(2017, 8, 5),\n",
    "                    start_date=dt(2000,1,1),\n",
    "                    #end_date=dt.today(),\n",
    "                    start_date_placeholder_text=\"YYYY,MM,DD\",\n",
    "                    end_date_placeholder_text=\"YYYY,MM,DD\",\n",
    "                ),\n",
    "                html.Div(id='output-container-date-picker-range')\n",
    "            ])\n",
    "    ]\n",
    "\n",
    "def register_marker(app):\n",
    "    \n",
    "    # MARKER\n",
    "    @app.callback(Output(NEW_MARKER, 'children'),\n",
    "                  [Input(MAP_ID, 'click_lat_lng')])\n",
    "    def new_marker(x):\n",
    "        if x is not None:\n",
    "            \n",
    "            global lat\n",
    "            global lon\n",
    "            lat, lon = x\n",
    "            print(\"Marker:\", lat)\n",
    "            \n",
    "            return dl.Marker(position=[lat, lon])\n",
    "        else:\n",
    "            return None\n",
    "    \n",
    "    # COORDINATES\n",
    "    @app.callback(Output(COORDINATE_CLICK_ID, 'children'),\n",
    "                  [Input(MAP_ID, 'click_lat_lng')])\n",
    "    def click_coord(e):\n",
    "        if e is not None:\n",
    "            print(\"Click:\", json.dumps(e))\n",
    "            return json.dumps(e)\n",
    "        else:\n",
    "            return \"-\"\n",
    "    \n",
    "    # BASE LAYER\n",
    "    @app.callback(Output(BASE_LAYER_ID, \"url\"),\n",
    "                  [Input(BASE_LAYER_DROPDOWN_ID, \"value\")])\n",
    "    def set_baselayer(url):\n",
    "        return url\n",
    "    \n",
    "    \n",
    "    # CLOUD\n",
    "    @app.callback(\n",
    "    Output(\"number-out\", \"children\"),\n",
    "    [Input(\"cloud\", \"value\")\n",
    "    ],) \n",
    "\n",
    "    def number_render(cloud):\n",
    "\n",
    "\n",
    "        if lat is not None:\n",
    "            \n",
    "            global latitude\n",
    "            latitude = lat\n",
    "        \n",
    "            global longitude\n",
    "            longitude = lon\n",
    "\n",
    "            global Maxcloud\n",
    "            Maxcloud = cloud \n",
    "            point = {'type':'Point', 'coordinates':[longitude, latitude]}; # This point is on turbid water\n",
    "            \n",
    "            #print(\"Cloud lat:\",lat, \"Type:\", type(lat))\n",
    "            #print(\"Cloud latitude:\",latitude, \"Type:\", type(latitude))\n",
    "            return ()\n",
    "    \n",
    "    # DATE\n",
    "    @app.callback(\n",
    "    dash.dependencies.Output('output-container-date-picker-range', 'children'),\n",
    "    [dash.dependencies.Input('my-date-picker-range', 'start_date'),\n",
    "     dash.dependencies.Input('my-date-picker-range', 'end_date')\n",
    "    ])\n",
    "\n",
    "    def update_output(start_date, end_date):\n",
    "        \n",
    "        # Define point\n",
    "        point = {'type':'Point', 'coordinates':[longitude, latitude]}; # This point is on turbid water\n",
    "        #print(\"Update Output Point\", point)\n",
    "\n",
    "        # Define Full Collection\n",
    "        fullCollection= makeLandsatSeries()\n",
    "        \n",
    "        # Filter collection by Lat, Lon & Cloud\n",
    "        filtered = fullCollection.filterBounds(ee.Geometry.Point(longitude,latitude)).filter(ee.Filter.lt('CLOUD_COVER', Maxcloud))\n",
    "\n",
    "        #Count Size // Total number of images: 165\n",
    "        count = int(filtered.size().getInfo())\n",
    "        #print(\"Update Output Count:\", count)\n",
    "\n",
    "        #Info\n",
    "        info = filtered.getRegion(point,500).getInfo()\n",
    "\n",
    "\n",
    "        if start_date is not None:\n",
    "            start_date = dt.strptime(start_date.split('T')[0], '%Y-%m-%d')\n",
    "            start_date_string = start_date.strftime('%Y-%m-%d')\n",
    "            startDate = start_date_string\n",
    "\n",
    "            end_date = dt.strptime(end_date.split('T')[0], '%Y-%m-%d')\n",
    "            end_date_string = end_date.strftime('%Y-%m-%d')\n",
    "            endDate = end_date_string\n",
    "\n",
    "            # Filter Collection with Lat, Lon & Cloud\n",
    "            filtered2 = filtered.filterDate(startDate, endDate)\n",
    "\n",
    "            #Count Size // Total number of images:\n",
    "            count = int(filtered2.size().getInfo())\n",
    "            print(\"Your inputs return\", count, \"images\")\n",
    "\n",
    "            info = filtered2.getRegion(point,500).getInfo()\n",
    "\n",
    "            # Datframe\n",
    "            df = pd.DataFrame(info,columns = ['id', 'longitude', 'latitude', 'time', 'blu', 'grn', 'red', 'nir', 'swir1', 'swir2', 'pixel_qa'])\n",
    "\n",
    "            # Create an ID column with NAN values\n",
    "            df['Satellite_ID'] = ('NAN')\n",
    "\n",
    "            # Make sure that all NaN values are `np.nan` not `'NAN'` (strings)\n",
    "            df = df.replace('NAN', np.nan)\n",
    "            mask = df['id'].str.contains(r'LT04')\n",
    "            df.loc[mask, 'Satellite_ID'] = ('L4')\n",
    "\n",
    "            mask = df['id'].str.contains(r'LT05')\n",
    "            df.loc[mask, 'Satellite_ID'] = ('L5')\n",
    "\n",
    "            mask = df['id'].str.contains(r'LT05')\n",
    "            df.loc[mask, 'Satellite_ID'] = ('L5')\n",
    "\n",
    "            mask = df['id'].str.contains(r'LE07')\n",
    "            df.loc[mask, 'Satellite_ID'] = ('L7')\n",
    "\n",
    "            mask = df['id'].str.contains(r'LC08')\n",
    "            df.loc[mask, 'Satellite_ID'] = ('L8')\n",
    "\n",
    "            # Drop First row (a duplicate of column header)\n",
    "            df = df.drop(df.index[0])\n",
    "\n",
    "            # The Earth Engine time stamp in milliseconds since the UNIX epoch.\n",
    "            # Link GEE: https://developers.google.com/earth-engine/glossary\n",
    "\n",
    "            # Convert UNIX to datetime\n",
    "            # Use pd.to_datetime() to convert unix epoch time\n",
    "            # Result is like this: 1994-03-17 06:11:20.254\n",
    "            df['time_stamp'] = pd.to_datetime(df['time'], unit='ms')\n",
    "\n",
    "            # Convert to String inorder to apply string split\n",
    "            df['time_string'] = df['time_stamp'].astype(str)\n",
    "\n",
    "            # make the new date column using string indexing [0:10] will give us the year,month,date part\n",
    "            # Result is like this 1994-03-17\n",
    "            df['Date'] = df['time_string'].str[0:10]\n",
    "\n",
    "            # Convert back to datetime\n",
    "            df['Date'] = pd.to_datetime(df['Date'])\n",
    "\n",
    "            # Drop unnecessary columns\n",
    "            df = df.drop('time_string', axis=1)\n",
    "\n",
    "            # Sort by Date\n",
    "            df = df.sort_values(by='Date')\n",
    "\n",
    "            # Calculate NDWI\n",
    "            #ndwi = (green - swir) / (green + swir)\n",
    "            df['NDWI'] = (df['grn'] - df['swir1']) / (df['grn'] + df['swir1'])\n",
    "            df['NDWI'] = pd.to_numeric(df['NDWI'])\n",
    "            \n",
    "            # Set Index\n",
    "            df = df.set_index('time_stamp')\n",
    "            \n",
    "            # CREATE YEARLY MEAN NDWI GRAPH\n",
    "            # New Dataframe: Set Mean NDWI & Time columns. Time column is from index\n",
    "            yearly_summary = pd.DataFrame()\n",
    "            yearly_summary['NDWI'] = df.NDWI.resample('Y').mean()\n",
    "\n",
    "            yearly_summary['Time'] = yearly_summary.index\n",
    "            print(yearly_summary)\n",
    "\n",
    "            # Create Line Chart\n",
    "            fig = px.line(yearly_summary,\n",
    "                          x = yearly_summary['Time'],\n",
    "                          y = yearly_summary['NDWI'])\n",
    "\n",
    "            # Fig Update & Set Title\n",
    "            fig.update_layout(title_text=\"Yearly Mean NDWI Values\")\n",
    "            fig.update_traces(overwrite=True)\n",
    "\n",
    "\n",
    "            #return \"start: {}, end: {}\".format(start_date_string, end_date_string) \n",
    "            return [\n",
    "                dcc.Graph(\n",
    "                    id=column,\n",
    "                    figure = fig\n",
    "                )\n",
    "                # check if column exists - user may have deleted it\n",
    "                # If `column.deletable=False`, then you don't\n",
    "                # need to do this check.\n",
    "                for column in [\"NDWI\"] if column in yearly_summary\n",
    "            ]\n",
    "\n",
    "\n",
    "# Layout\n",
    "def generate_layout():\n",
    "    dlayout=html.Div([\n",
    "        html.P('Satellite Image Analysis'),\n",
    "        html.P(\"Select Location\"),\n",
    "        html.Div([\n",
    "            html.P('Map Base Layer'),\n",
    "            dcc.Dropdown(\n",
    "                id=BASE_LAYER_DROPDOWN_ID,\n",
    "                options=[{\"label\": i, \"value\": mapbox_url.format(id=i, access_token=mapbox_token)} for i in mapbox_ids],\n",
    "                value=mapbox_url.format(id=\"light-v9\", access_token=mapbox_token)\n",
    "            ),\n",
    "            html.P('Refine Date Range'),\n",
    "            html.P('Opacity:')\n",
    "        ],style={'float':'left','width':'20%','margin-right':'15px'}),\n",
    "        html.Div(render_marker(),style={'float':'left','width':'75%'})\n",
    "    ])\n",
    "    \n",
    "    return dlayout\n",
    "\n",
    "\n",
    "##-----------------------------------------##\n",
    "#               App\n",
    "##-----------------------------------------##\n",
    "app = dash.Dash(__name__, external_scripts=['https://codepen.io/chriddyp/pen/bWLwgP.css'])\n",
    "\n",
    "# Create layout.\n",
    "app.layout = html.Div(generate_layout())\n",
    "\n",
    "# Bind callbacks.\n",
    "register_marker(app)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run_server(debug=False, port=8150)\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
